package com.starview.star.compiler.sources;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import com.starview.platform.data.value.ResourceURI;
import com.starview.platform.resource.ResourceException;
import com.starview.platform.resource.Resources;
import com.starview.star.code.repository.CodeParser;
import com.starview.star.code.repository.CodeTree;
import com.starview.star.compiler.ErrorReport;
import com.starview.star.compiler.format.rules.FmtProgram;
import com.starview.star.compiler.operator.Operators;
import com.starview.star.compiler.util.PrettyPrintDisplay;
import com.starview.star.compiler.wff.WffProgram;

/**
 * Collect together the meta rules from a Star source package
 * 
 * @author fgm
 * 
 */
@SuppressWarnings("serial")
public class MetaRules implements CodeTree, CodeParser
{
  public static final String MANIFEST = "metarules";
  public static final String EXTENSION = "metarules";

  public static final String entryType = "metaRules";
  private final ResourceURI uri;
  private final String name;
  private final Operators operators;
  private final String macroEntry;
  private final WffProgram wffRules;
  private final FmtProgram fmtRules;

  // Constructor for use as a MetaRulesParser
  public MetaRules()
  {
    this(null, null, null, null, null, null);
  }

  public MetaRules(ResourceURI uri, String name, Operators operators, String macroEntry, WffProgram wffRules,
      FmtProgram fmtRules)
  {
    this.uri = uri;
    this.name = name;
    this.macroEntry = macroEntry;
    this.wffRules = wffRules;
    this.fmtRules = fmtRules;
    this.operators = operators;
  }

  @Override
  public String getPath()
  {
    return uri.getPath();
  }

  public String getName()
  {
    return name;
  }

  public String getMacroEntry()
  {
    return macroEntry;
  }

  public Operators getOperators()
  {
    return operators;
  }

  public WffProgram getWffRules()
  {
    return wffRules;
  }

  public FmtProgram getFmtRules()
  {
    return fmtRules;
  }

  @Override
  public void prettyPrint(PrettyPrintDisplay disp)
  {
    disp.appendId(getName());
    int mark = disp.markIndent(2);
    disp.append(" is meta{\n");

    operators.prettyPrint(disp);
    fmtRules.prettyPrint(disp);
    wffRules.prettyPrint(disp);
    disp.popIndent(mark);
    disp.append("}\n");
  }

  @Override
  public String toString()
  {
    return PrettyPrintDisplay.toString(this);
  }

  @Override
  public void write(File file) throws IOException
  {
    FileOutputStream fos = new FileOutputStream(file);
    ObjectOutputStream oostream = new ObjectOutputStream(fos);
    oostream.writeObject(this);
    oostream.close();
  }

  @Override
  public CodeTree parse(ResourceURI uri, ErrorReport errors)
  {
    MetaRules newMetaRules = null;
    try (InputStream fis = Resources.getInputStream(uri)) {
      return parse(uri, fis, errors);
    } catch (ResourceException | IOException e) {
      errors.reportError("Resource problem: " + e.getMessage());
    }
    return newMetaRules;
  }

  @Override
  public CodeTree parse(ResourceURI uri, InputStream stream, ErrorReport errors) throws ResourceException
  {
    ObjectInputStream in = null;
    MetaRules newMetaRules = null;
    try {
      in = new ObjectInputStream(stream);
      try {
        newMetaRules = (MetaRules) in.readObject();
      } catch (IOException ex) {
        errors.reportError("IOException: " + ex.getMessage());
      } catch (ClassNotFoundException ex) {
        errors.reportError("ClassNotFoundException: " + ex.getMessage());
      } finally {
        try {
          in.close();
        } catch (IOException e) {
          errors.reportError("IOException: " + e.getMessage());
        }
      }
    } catch (IOException ex) {
      errors.reportError("IOException: " + ex.getMessage());
    }
    return newMetaRules;
  }

  @Override
  public String getExtension()
  {
    return EXTENSION;
  }
}
